﻿//-----------------------------------------------------------------------
// <Copyright>
// * Copyright (C) 2022 RuYiAdmin All Rights Reserved
// </Copyright>
//-----------------------------------------------------------------------

using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using RuYiAdmin.Net.DataModel.DataTransformationModel.Sys;
using RuYiAdmin.Net.DataModel.EntityDataModel.Sys;
using RuYiAdmin.Net.DataModel.HttpSession;
using RuYiAdmin.Net.SystemService.BusinessService.Interface.Framework;
using RuYiAdmin.Net.SystemService.BusinessService.Interface.Sys;
using RuYiAdmin.Net.UniversalFoundation.Configurations;
using RuYiAdmin.Net.UniversalFoundation.Constants.Sys;
using RuYiAdmin.Net.UniversalFoundation.Enums.Business;
using RuYiAdmin.Net.UniversalFoundation.Enums.Framework;
using RuYiAdmin.Net.UniversalFoundation.Exceptions.Framework;
using RuYiAdmin.Net.UniversalFoundation.GeneralFoundationClass;
using RuYiAdmin.Net.UniversalFoundation.Models;
using RuYiAdmin.Net.UniversalFoundation.Utils;
using RuYiAdmin.Net.WebApi.RuYiAdminCode.RuYiAdminAnnotation;
using RuYiAdmin.Net.WebApi.RuYiAdminCode.RuYiAdminBase;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace RuYiAdmin.Net.WebApi.RuYiAdminController.Sys
{
    /// <summary>
    /// 通知公告管理控制器
    /// </summary>
    public class SysAnnouncementManagementController : RuYiAdminBaseController<SysAnnouncement>
    {
        #region 属性及构造函数

        /// <summary>
        /// 通知公告业务接口实例
        /// </summary>
        private readonly ISysAnnouncementService AnnouncementService;

        /// <summary>
        /// AutoMapper实例
        /// </summary>
        private readonly IMapper AutoMapper;

        /// <summary>
        /// 收件人服务层接口实例
        /// </summary>
        private readonly ISysAddresseeService AddresseeService;

        /// <summary>
        /// 系统用户服务层接口实例
        /// </summary>
        private readonly ISysUserService UserService;

        /// <summary>
        /// 系统附件服务层接口实例
        /// </summary>
        private readonly ISysAttachmentService AttachmentService;

        /// <summary>
        /// MQ接口实例
        /// </summary>
        private readonly IMQService MQService;

        /// <summary>
        /// Nest接口实例
        /// </summary>
        private readonly INestService NestService;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="AnnouncementService"></param>
        /// <param name="AutoMapper"></param>
        /// <param name="AddresseeService"></param>
        /// <param name="UserService"></param>
        /// <param name="AttachmentService"></param>
        /// <param name="MQService"></param>
        /// <param name="NestService"></param>
        public SysAnnouncementManagementController(ISysAnnouncementService AnnouncementService,
                                                IMapper AutoMapper,
                                                ISysAddresseeService AddresseeService,
                                                ISysUserService UserService,
                                                ISysAttachmentService AttachmentService,
                                                IMQService MQService,
                                                INestService NestService) : base(AnnouncementService)
        {
            this.AnnouncementService = AnnouncementService;
            this.AutoMapper = AutoMapper;
            this.AddresseeService = AddresseeService;
            this.UserService = UserService;
            this.AttachmentService = AttachmentService;
            this.MQService = MQService;
            this.NestService = NestService;
        }

        #endregion

        #region 查询通知公告列表

        /// <summary>
        /// 查询通知公告列表
        /// </summary>
        /// <param name="searchCondition">查询条件</param>
        /// <returns>QueryResponseResult</returns>
        [HttpPost]
        [RuYiAdminOperationLog(OperationType.QueryList)]
        [RuYiAdminPermission("announcement:query:list")]
        public async Task<IActionResult> Post(SearchCondition searchCondition)
        {
            var queryResponseResult = new QueryResponseResult<SysAnnouncement>();

            if (RuYiGlobalConfig.AnnouncementConfig.IsElasticsearchEnabled)
            {
                searchCondition.SearchItems.Add(new SearchItem("isDel", DataType.Int, SearchMethod.Equal, 0));
                var searchRequest = searchCondition.ToSearchRequest<SysAnnouncement>();//转化查询条件                
                var response = await this.NestService.GetElasticClient().SearchAsync<SysAnnouncement>(searchRequest);//查询Elasticsearch数据
                //if (!response.IsValidResponse)
                //{
                //    throw new RuYiAdminCustomException(response.DebugInformation);
                //}
                var announcements = response.Documents.ToList();
                queryResponseResult = QueryResponseResult<SysAnnouncement>.Success((int)response.Total, announcements);
            }
            else
            {
                queryResponseResult = await AnnouncementService.SqlQueryAsync(searchCondition, "sqls:sql:query_sysannouncement");
            }

            return Ok(queryResponseResult);
        }

        #endregion

        #region 按编号获取通知公告

        /// <summary>
        /// 按编号获取通知公告
        /// </summary>
        /// <param name="id">通知公告编号</param>
        /// <returns>ActionResponseResult</returns>
        [HttpGet("{id}")]
        [RuYiAdminOperationLog(OperationType.QueryEntity)]
        [RuYiAdminPermission("announcement:query:list,sys:announcement:query:list,notification:query:list")]
        public async Task<IActionResult> GetById(Guid id)
        {
            var actionResponseResult = new ActionResponseResult();

            if (RuYiGlobalConfig.AnnouncementConfig.IsElasticsearchEnabled)
            {
                var response = await this.NestService.GetElasticClient().GetAsync<SysAnnouncement>(id);
                if (!response.IsValidResponse)
                {
                    throw new RuYiAdminCustomException(response.DebugInformation);
                }
                actionResponseResult = ActionResponseResult.OK(response.Source);
            }
            else
            {
                actionResponseResult = await AnnouncementService.GetByIdAsync(id);
            }

            return Ok(actionResponseResult);
        }

        #endregion

        #region 添加通知公告

        /// <summary>
        /// 添加通知公告
        /// </summary>
        /// <param name="announcementDTO">通知公告</param>
        /// <returns>ActionResponseResult</returns>
        [HttpPost]
        [RuYiAdminOperationLog(OperationType.AddEntity)]
        [RuYiAdminPermission("announcement:add:entity")]
        public async Task<IActionResult> Add([FromBody] SysAnnouncementDTO announcementDTO)
        {
            var actionResponseResult = new ActionResponseResult();

            var announcement = AutoMapper.Map<SysAnnouncement>(announcementDTO);//数据转化
            if (RuYiGlobalConfig.AnnouncementConfig.IsElasticsearchEnabled)
            {
                announcement.Create(this.HttpContext);
                var response = await this.NestService.GetElasticClient().IndexAsync(announcement);//保存数据到Elasticsearch
                if (!response.IsValidResponse)
                {
                    throw new RuYiAdminCustomException(response.DebugInformation);
                }
                actionResponseResult = ActionResponseResult.OK(announcement);
            }
            else
            {
                actionResponseResult = await AnnouncementService.AddAsync(announcement);//保存数据
            }
            await SengMailAndMessageAsync(announcementDTO);//保存通知收件人并发送邮件

            return Ok(actionResponseResult);
        }

        #endregion

        #region 编辑通知公告

        /// <summary>
        /// 编辑通知公告
        /// </summary>
        /// <param name="announcementDTO">通知公告</param>
        /// <returns>ActionResponseResult</returns>
        [HttpPut]
        [RuYiAdminOperationLog(OperationType.EditEntity)]
        [RuYiAdminPermission("announcement:edit:entity")]
        public async Task<IActionResult> Edit([FromBody] SysAnnouncementDTO announcementDTO)
        {
            var actionResponseResult = new ActionResponseResult();

            var announcement = AutoMapper.Map<SysAnnouncement>(announcementDTO);
            if (RuYiGlobalConfig.AnnouncementConfig.IsElasticsearchEnabled)
            {
                var response = await this.NestService.GetElasticClient().GetAsync<SysAnnouncement>(announcement.Id);
                if (!response.IsValidResponse)
                {
                    throw new RuYiAdminCustomException(response.DebugInformation);
                }
                var originalAnnouncement = response.Source;

                if (!originalAnnouncement.VersionId.Equals(announcement.VersionId))
                {
                    throw new RuYiAdminCustomException(ExceptionMessage.DirtyDataExceptionMessage);
                }
                else
                {
                    announcement.Modify(this.HttpContext);
                    var editResponse = await this.NestService.GetElasticClient().IndexAsync(announcement);//保存数据到Elasticsearch
                    if (!editResponse.IsValidResponse)
                    {
                        throw new RuYiAdminCustomException(editResponse.DebugInformation);
                    }
                    actionResponseResult = ActionResponseResult.OK(announcement);
                }
            }
            else
            {
                actionResponseResult = await AnnouncementService.UpdateAsync(announcement);
            }

            #region 删除收件人

            var searchCondition = new SearchCondition();
            searchCondition.SearchItems = new List<SearchItem>();
            searchCondition.SearchItems.Add(new SearchItem()
            {
                Field = "BusinessId",
                SearchMethod = SearchMethod.Equal,
                DataType = DataType.Guid,
                Value = announcement.Id
            });
            var list = AddresseeService.GetList(searchCondition).List;
            foreach (var addressee in list)
            {
                await AddresseeService.DeleteAsync(addressee.Id);
            }

            #endregion

            await SengMailAndMessageAsync(announcementDTO);//保存通知收件人并发送邮件

            return Ok(actionResponseResult);
        }

        #endregion

        #region 批量删除通知公告

        /// <summary>
        /// 批量删除通知公告
        /// </summary>
        /// <param name="ids">数组串</param>
        /// <returns>ActionResponseResult</returns>
        [HttpDelete("{ids}")]
        [RuYiAdminOperationLog(OperationType.DeleteEntity)]
        [RuYiAdminPermission("announcement:del:entities")]
        public async Task<IActionResult> Delete(string ids)
        {
            var actionResponseResult = new ActionResponseResult();

            var array = ids.GetGuidArray();
            if (RuYiGlobalConfig.AnnouncementConfig.IsElasticsearchEnabled)
            {
                foreach (var id in array)
                {
                    var response = await this.NestService.GetElasticClient().GetAsync<SysAnnouncement>(id);
                    if (!response.IsValidResponse)
                    {
                        throw new RuYiAdminCustomException(response.DebugInformation);
                    }
                    else
                    {
                        response.Source.Delete(this.HttpContext);//删除Elasticsearch中的数据
                        var updateResponse = await this.NestService.GetElasticClient().IndexAsync(response.Source);//保存数据到Elasticsearch
                        if (!updateResponse.IsValidResponse)
                        {
                            throw new RuYiAdminCustomException(updateResponse.DebugInformation);
                        }
                    }
                }
                actionResponseResult = ActionResponseResult.OK();
            }
            else
            {
                actionResponseResult = await AnnouncementService.DeleteRangeAsync(array);//批量删除通知公告
            }

            foreach (var item in array)
            {
                var searchCondition = new SearchCondition();
                searchCondition.SearchItems = new List<SearchItem>();
                searchCondition.SearchItems.Add(new SearchItem()
                {
                    Field = "BusinessId",
                    SearchMethod = SearchMethod.Equal,
                    DataType = DataType.Guid,
                    Value = item
                });
                var list = AddresseeService.GetList(searchCondition).List;
                foreach (var addressee in list)
                {
                    //删除收件人
                    actionResponseResult = await AddresseeService.DeleteAsync(addressee.Id);
                }
            }

            return Ok(actionResponseResult);
        }

        #endregion

        #region 获取通知公告收件人

        /// <summary>
        /// 获取通知公告收件人
        /// </summary>
        /// <param name="id">通知公告编号</param>
        /// <returns>ActionResponseResult</returns>
        [HttpGet("{id}")]
        [RuYiAdminOperationLog(OperationType.QueryList)]
        [RuYiAdminPermission("announcement:edit:entity")]
        public async Task<IActionResult> GetAnnouncementAddressee(Guid id)
        {
            var searchCondition = new SearchCondition();
            searchCondition.SearchItems = new List<SearchItem>();
            searchCondition.SearchItems.Add(new SearchItem()
            {
                Field = "BusinessId",
                SearchMethod = SearchMethod.Equal,
                DataType = DataType.Guid,
                Value = id
            });

            var actionResponseResult = await AddresseeService.GetListAsync(searchCondition);
            return Ok(actionResponseResult);
        }

        #endregion

        #region 查询公告列表

        /// <summary>
        /// 查询公告列表
        /// </summary>
        /// <param name="searchCondition">查询条件</param>
        /// <returns>ActionResponseResult</returns>
        [HttpPost]
        [RuYiAdminOperationLog(OperationType.QueryList)]
        [RuYiAdminPermission("sys:announcement:query:list")]
        public async Task<IActionResult> GetAnnouncements(SearchCondition searchCondition)
        {
            var queryResponseResult = new QueryResponseResult<SysAnnouncement>();

            if (RuYiGlobalConfig.AnnouncementConfig.IsElasticsearchEnabled)
            {
                searchCondition.SearchItems.Add(new SearchItem("isDel", DataType.Int, SearchMethod.Equal, 0));
                searchCondition.SearchItems.Add(new SearchItem("type", DataType.Int, SearchMethod.Equal, 0));
                searchCondition.SearchItems.Add(new SearchItem("status", DataType.Int, SearchMethod.Equal, 0));
                var searchRequest = searchCondition.ToSearchRequest<SysAnnouncement>();//转化查询条件                
                var response = await this.NestService.GetElasticClient().SearchAsync<SysAnnouncement>(searchRequest);//查询Elasticsearch数据
                //if (!response.IsValidResponse)
                //{
                //    throw new RuYiAdminCustomException(response.DebugInformation);
                //}
                var announcements = response.Documents.ToList();
                queryResponseResult = QueryResponseResult<SysAnnouncement>.Success((int)response.Total, announcements);
                return Ok(queryResponseResult);
            }
            else
            {
                queryResponseResult = await AnnouncementService.SqlQueryAsync(searchCondition, "sqls:sql:query_sys_announcement");
                return Ok(queryResponseResult);
            }
        }

        #endregion

        #region 查询通知列表

        /// <summary>
        /// 查询通知列表
        /// </summary>
        /// <param name="searchCondition">查询条件</param>
        /// <returns>ActionResponseResult</returns>
        [HttpPost]
        [RuYiAdminOperationLog(OperationType.QueryList)]
        [RuYiAdminPermission("notification:query:list")]
        public async Task<IActionResult> GetNotifications(SearchCondition searchCondition)
        {
            var queryResponseResult = new QueryResponseResult<SysNotificationDTO>();

            if (RuYiGlobalConfig.AnnouncementConfig.IsElasticsearchEnabled)
            {
                var user = RuYiSessionContext.GetCurrentUserInfo(this.HttpContext);
                SearchCondition addresseeSearchCondition = new SearchCondition();
                addresseeSearchCondition.AddDefaultSearchItem();
                addresseeSearchCondition.SearchItems.Add(new SearchItem()
                {
                    Field = "UserId",
                    SearchMethod = SearchMethod.Equal,
                    DataType = DataType.Guid,
                    Value = user.Id
                });
                var addressees = (await this.AddresseeService.GetListAsync(addresseeSearchCondition)).List;
                if (addressees.Count > 0)
                {
                    searchCondition.SearchItems.Add(new SearchItem("isDel", DataType.Int, SearchMethod.Equal, 0));
                    searchCondition.SearchItems.Add(new SearchItem("type", DataType.Int, SearchMethod.Equal, 1));
                    searchCondition.SearchItems.Add(new SearchItem("status", DataType.Int, SearchMethod.Equal, 0));
                    searchCondition.SearchItems.Add(new SearchItem("id", DataType.String, SearchMethod.Include,
                            String.Join(", ", addressees.Select(t => t.BusinessId).ToList())));
                    var searchRequest = searchCondition.ToSearchRequest<SysAnnouncement>();//转化查询条件                
                    var response = await this.NestService.GetElasticClient().SearchAsync<SysAnnouncement>(searchRequest);//查询Elasticsearch数据
                    //if (!response.IsValidResponse)
                    //{
                    //    throw new RuYiAdminCustomException(response.DebugInformation);
                    //}
                    var announcements = response.Documents.ToList();
                    List<SysNotificationDTO> notifications = new List<SysNotificationDTO>();
                    foreach (var announcement in announcements)
                    {
                        SysNotificationDTO notification = new SysNotificationDTO();
                        notification = this.AutoMapper.Map<SysNotificationDTO>(announcement);//数据转化

                        SysAddressee addressee = addressees.Where(t => t.BusinessId.Equals(announcement.Id)).FirstOrDefault();
                        if (addressee != null)
                        {
                            notification.Readed = addressee.Status;
                        }
                        else
                        {
                            notification.Readed = -1;
                        }

                        notifications.Add(notification);
                    }
                    queryResponseResult = QueryResponseResult<SysNotificationDTO>.Success((int)response.Total, notifications);
                    return Ok(queryResponseResult);
                }
                return Ok(QueryResponseResult<SysAnnouncement>.OK(0, null));
            }
            else
            {
                queryResponseResult = await AnnouncementService.QueryNotifications(searchCondition, "sqls:sql:query_sys_notification");
                return Ok(queryResponseResult);
            }
        }

        #endregion

        #region 更改通知收件人阅读状态

        /// <summary>
        /// 更改通知收件人阅读状态
        /// </summary>
        /// <param name="notificationId">通知编号</param>
        /// <returns>ActionResponseResult</returns>
        [HttpGet("{notificationId}")]
        [RuYiAdminOperationLog(OperationType.EditEntity)]
        [RuYiAdminPermission("notification:query:list")]
        public async Task<IActionResult> UpdateNotificationStatus(Guid notificationId)
        {
            var actionResponseResult = await AddresseeService.UpdateNotificationStatus(notificationId);
            return Ok(actionResponseResult);
        }

        #endregion

        #region 发送邮件与及时消息

        private async Task SengMailAndMessageAsync(SysAnnouncementDTO announcementDTO)
        {
            if (announcementDTO.Type == 0 && announcementDTO.Status == 0)
            {
                #region 发送及时消息

                var msg = new SystemMessage();
                msg.Message = "Announcement";
                msg.MessageType = MessageType.Announcement;
                msg.Object = new { announcementDTO.Title };

                MQService.SendTopic(JsonConvert.SerializeObject(msg));

                #endregion
            }
            else if (announcementDTO.Type == 1 && !string.IsNullOrEmpty(announcementDTO.Addressee))
            {
                #region 发送邮件与及时消息

                var array = announcementDTO.Addressee.GetGuidArray();

                #region 保存收件人

                var addressee = new List<SysAddressee>();
                foreach (var item in array)
                {
                    var addr = new SysAddressee();
                    addr.BusinessId = announcementDTO.Id;
                    addr.UserId = item;
                    addr.Status = 0;
                    addressee.Add(addr);
                }
                await AddresseeService.AddListAsync(addressee);

                #endregion

                #region 发送及时消息

                addressee.ForEach(item =>
                {
                    var msg = new SystemMessage();
                    msg.Message = "Notification";
                    msg.MessageType = MessageType.Notification;
                    msg.Object = new { item.UserId, announcementDTO.Title };

                    MQService.SendTopic(JsonConvert.SerializeObject(msg));
                });

                #endregion

                //发送邮件
                if (announcementDTO.SendMail && announcementDTO.Status == 0 && addressee.Count > 0)
                {
                    foreach (var item in array)
                    {
                        var user = UserService.GetById(item).Object as SysUser;
                        if (!string.IsNullOrEmpty(user.Email))
                        {
                            //获取附件列表
                            var attachments = AttachmentService.GetList().Object as List<SysAttachment>;
                            attachments = attachments.FindAll(t => t.BusinessId == announcementDTO.Id && t.IsDel == (int)DeletionType.Undeleted);

                            //加载附件信息
                            List<FileInfo> files = new List<FileInfo>();
                            foreach (var att in attachments)
                            {
                                files.Add(new FileInfo(att.FilePath));
                            }

                            //发送邮件
                            RuYiMailUtil.SendMail(announcementDTO.Title, announcementDTO.Content, user.Email, files, true);
                        }
                    }
                }

                #endregion
            }
        }

        #endregion
    }
}
